package com.dropdb.demo.config;

import com.dropdb.demo.bean.Admin;
import com.dropdb.demo.bean.Log;
import com.dropdb.demo.bean.Order;
import com.dropdb.demo.bean.User;
import com.dropdb.demo.bean.vo.AdminData;
import com.dropdb.demo.bean.vo.BaseRespVO;
import com.dropdb.demo.mapper.LogMapper;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.*;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "com.dropdb.demo.controller")
@Component
@Aspect
public class LoggerAspectConfig {

    @Autowired
    RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Autowired
    LogMapper logMapper;

    @Pointcut("execution(* com..controller.admin..login(..))" +
            "|| execution(* com..controller.admin..logout(..))" +
            "|| execution(* com..controller.admin.AdminAdminController.update(..))" +
            "|| execution(* com..controller.admin.AdminAdminController.create(..))" +
            "|| execution(* com..controller.admin.AdminAdminController.delete(..))" +
            "|| execution(* com..controller.admin..orderShip(..))")
    public void point() {}

    private final static Map<String, String> ACTION;
    static {
        HashMap<String, String> map = new HashMap<>();
        map.put("/admin/auth/login", "登录");
        map.put("/admin/auth/logout", "退出");
        map.put("/admin/admin/update", "编辑管理员");
        map.put("/admin/admin/create", "添加管理员");
        map.put("/admin/admin/delete", "删除管理员");
        map.put("/admin/order/ship", "发货");
        ACTION = Collections.unmodifiableMap(map);
    }
    private final static Map<String, Method> RESULTCALLBACK;
    static {
        HashMap<String, Method> map = new HashMap<>();
        try {
            Method getUsername = AdminData.class.getMethod("getUsername");
            map.put("/admin/admin/update", getUsername);
            map.put("/admin/admin/create", getUsername);
            //Method getOrderSn = Order.class.getMethod("getOrderSn");
            Method getId = Order.class.getMethod("getId");
            map.put("/admin/order/ship", getId);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        RESULTCALLBACK = Collections.unmodifiableMap(map);
    }
    private final static Map<String, String> RESULTPREFIX;
    static {
        HashMap<String, String> map = new HashMap<>();
        map.put("/admin/order/ship", "订单编号\n");
        RESULTPREFIX = Collections.unmodifiableMap(map);
    }

    @Around("point()")
    public BaseRespVO around(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest req = requestAttributes.getRequest();
        Log log = new Log();
        String uri = req.getRequestURI();

        //delete username先获取
        String deleteUsername = null;
        if ("/admin/admin/delete".equals(uri)) {

            List<Object> argss = Arrays.asList(joinPoint.getArgs());
            for (Object o : argss) {
                if (o instanceof Admin) {
                    deleteUsername = ((Admin) o).getUsername();
                }
            }
        }
        String action = ACTION.get(uri);
        BaseRespVO vo = null;
        try {
            if (null == action) {
                return (BaseRespVO) joinPoint.proceed();
            } else {
                //没有设置用户名
                log.setAction(action);
                log.setAddTime(new Date());
                log.setUpdateTime(log.getAddTime());
                log.setIp(req.getRemoteAddr());
                log.setType(1);

                if ("/admin/auth/logout".equals(uri)) {
                    //设置用户名
                    Admin admin = (Admin) SecurityUtils.getSubject().getPrincipal(); //没登录需要非空检查
                    if (null == admin) {
                        return BaseRespVO.error(501, "请登录");
                    }
                    log.setAdmin(admin.getUsername());
                }

                vo = (BaseRespVO) joinPoint.proceed();
                log.setStatus(0 == vo.getErrno());

                if (!"/admin/auth/logout".equals(uri)) {
                    //设置用户名
                    Admin admin = (Admin) SecurityUtils.getSubject().getPrincipal(); //没登录需要非空检查
                    if (null == admin) {
                        return BaseRespVO.error(501, "请登录");
                    }
                    log.setAdmin(admin.getUsername());
                }

                Method method = RESULTCALLBACK.get(uri);
                if (null != method) {
                    String result = "";
                    if (null != vo.getData()) {
//                        result = (String) method.invoke(vo.getData());
                        Object rslt = method.invoke(vo.getData());
                        if (rslt instanceof Integer) {
                            result = String.valueOf(rslt);
                        } else {
                            result = (String) rslt;
                        }
                    }
                    String prefix = RESULTPREFIX.get(uri);
                    if (null != prefix) {
                        log.setResult(prefix + result);
                    } else {
                        log.setResult(result);
                    }
                } else {
                    if (null != deleteUsername) {
                        log.setResult(deleteUsername);
                    } else {
                        log.setResult("");
                    }
                }
                log.setComment("");
                logMapper.insertSelective(log);
            }
        } catch (Throwable throwable) {
            //throwable.printStackTrace();
            throw throwable;
        }
        return vo;
    }
}
